#include "core.h"


bool LSR_is_init = false;

/*
 * Initial namespace map.
 */
static char *nsm_str[][2] = {
    {"ebucore", "http://www.ebu.ch/metadata/ontologies/ebucore/ebucore#"},
    {"rsrc", LSR_RSRC_PFX},
    {"lsup", "http://data.knowledgetx.com/onto/lsup#"},
    {"premis", "http://www.loc.gov/premis/rdf/v1#"},
    {NULL, NULL}
};

/*
 * Repo-managed predicates.
 */
static char *mgd_pred_str[] = {
    "ebucore:hasMimeType",
    "lsup:created",
    "lsup:createdBy",
    "lsup:lastModified",
    "lsup:lastModifiedBy",
    "ore:proxyIn",
    "ore:proxyFor",
    "premis:hasSize",
    "premis:hasMessageDigest",
    NULL
};

/*
 * Repo-managed RDF types.
 */
static char *mgd_type_str[] = {
    "lsup:AdminMetadata",
    "lsup:DataResource",
    "lsup:DescriptiveResource",
    "lsup:List",
    "lsup:ListItem",
    "lsup:Metadata",
    "lsup:Resource",
    "lsup:Set",
    "lsup:UserMetadata",
    "ore:Aggregation",
    "ore:Proxy",
    NULL
};


LSR_TermMap *LSR_managed_preds, *LSR_managed_types;


/*
 * Callbacks.
 */

/// Hash function for term map.
static uint64_t tmap_hash_fn (const void *item, uint64_t seed0, uint64_t seed1)
{ return LSUP_term_hash ((LSUP_Term *) item); }


/// Compare function for term map.
static int tmap_cmp_fn (const void *a, const void *b, void *udata)
{
    const LSUP_Term *ta = a, *tb = b;
    return strcmp(ta->data, tb->data);
}


/// Free element within the term map.
static void tmap_free_fn (void *item)
{ LSUP_term_free ((LSUP_Term *) item); }


LSUP_rc LSR_init (void)
{
    if (LSR_is_init) return LSUP_NOACTION;

    LSUP_rc rc = LSUP_init();
    if (rc < 0) return rc;

    // Load additional LSUP_repo namespaces into store and memory.
    LSUP_NSMap *nsm = LSUP_default_env->nsm;

    for (int i = 0; nsm_str[i][0] != NULL; i++)
        LSUP_nsmap_add (nsm, nsm_str[i][0], nsm_str[i][1]);

    // Store the additional NS if this is the first time.
    LSUP_mdbstore_nsm_store (LSUP_default_env->mdb_store, nsm);

    // Cache managed predicates.
    LSR_managed_preds = hashmap_new (
            sizeof (LSUP_Term), 0, HASH_SEED, 0,
            tmap_hash_fn, tmap_cmp_fn, tmap_free_fn, NULL);
    for (int i = 0; mgd_pred_str[i] != NULL; i++) {
        LSUP_Term *uri = LSUP_iriref_new (
                mgd_pred_str[i], LSUP_default_env->nsm);

        hashmap_set (LSR_managed_preds, uri);
    }

    // Cache managed types.
    LSR_managed_types = hashmap_new (
            sizeof (LSUP_Term), 0, HASH_SEED, 0,
            tmap_hash_fn, tmap_cmp_fn, tmap_free_fn, NULL);
    for (int i = 0; mgd_type_str[i] != NULL; i++) {
        LSUP_Term *uri = LSUP_iriref_new (
                mgd_type_str[i], LSUP_default_env->nsm);

        hashmap_set (LSR_managed_types, uri);
    }
    LSR_is_init = true;

    atexit (LSR_done);

    return LSUP_OK;
}


void LSR_done (void)
{
    if (!LSR_is_init) return;

    log_info ("Tearing down LSUP repo environment.");

    LSR_TermMap *entry, *tmp;
    HASH_ITER (hh, LSR_managed_preds, entry, tmp) {
        HASH_DEL (LSR_managed_preds, entry);
        LSUP_term_free (entry->term);
        free (entry);
    }
    HASH_ITER (hh, LSR_managed_types, entry, tmp) {
        HASH_DEL (LSR_managed_types, entry);
        LSUP_term_free (entry->term);
        free (entry);
    }

    hashmap_free (LSR_managed_preds);
    hashmap_free (LSR_managed_types);
    LSUP_done();
    LSR_is_init = false;
}


LSUP_Term *LSR_id_to_urn (const uuid_t id, const char *frag);
